package top.codecrab.javase;

import java.util.concurrent.*;

/**
 * @author codecrab
 * @since 2021年06月26日 9:20
 */
public class SingletonTest {

    public static void main(String[] args) {
        SingletonTest test = new SingletonTest();
        test.testHungry1();
        test.testHungry2();
        test.testHungry3();
        try {
            test.testLazy1();
            test.testLazy2();
            test.testLazy3();
            test.testLazy4();
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    void testHungry1() {
        Singleton.Hungry.Hungry1 instance = Singleton.Hungry.Hungry1.INSTANCE;
        System.out.println(instance);
    }

    void testHungry2() {
        Singleton.Hungry.Hungry2 instance = Singleton.Hungry.Hungry2.INSTANCE;
        System.out.println(instance);
    }

    void testHungry3() {
        Singleton.Hungry.Hungry3 instance = Singleton.Hungry.Hungry3.INSTANCE;
        System.out.println(instance);
    }

    /**
     * 结论：线程睡眠时间越长，越大概率为false，不安全
     */
    void testLazy1() throws ExecutionException, InterruptedException {
        //创建两个线程，测试线程是否安全
        Callable<Singleton.Lazy.Lazy1> c1 = Singleton.Lazy.Lazy1::getInstance;
        Callable<Singleton.Lazy.Lazy1> c2 = Singleton.Lazy.Lazy1::getInstance;

        ExecutorService service = Executors.newFixedThreadPool(2);
        Future<Singleton.Lazy.Lazy1> f1 = service.submit(c1);
        Future<Singleton.Lazy.Lazy1> f2 = service.submit(c2);
        Singleton.Lazy.Lazy1 lazy1 = f1.get();
        Singleton.Lazy.Lazy1 lazy2 = f2.get();

        System.out.println(lazy1 == lazy2);
    }

    /**
     * 结论：线程睡眠时间不管多少，线程始终是安全的，由于每次调用方法都会加锁释放锁，性能有影响
     */
    void testLazy2() throws ExecutionException, InterruptedException {
        //创建两个线程，测试线程是否安全
        Callable<Singleton.Lazy.Lazy2> c1 = Singleton.Lazy.Lazy2::getInstance;
        Callable<Singleton.Lazy.Lazy2> c2 = Singleton.Lazy.Lazy2::getInstance;

        ExecutorService service = Executors.newFixedThreadPool(2);
        Future<Singleton.Lazy.Lazy2> f1 = service.submit(c1);
        Future<Singleton.Lazy.Lazy2> f2 = service.submit(c2);
        Singleton.Lazy.Lazy2 lazy1 = f1.get();
        Singleton.Lazy.Lazy2 lazy2 = f2.get();

        System.out.println(lazy1 == lazy2);
    }

    /**
     * 结论：在同步代码块外再加一个判断，那么同步代码块执行的次数就会大大减少
     */
    void testLazy3() throws ExecutionException, InterruptedException {
        //创建两个线程，测试线程是否安全
        Callable<Singleton.Lazy.Lazy3> c1 = Singleton.Lazy.Lazy3::getInstance;
        Callable<Singleton.Lazy.Lazy3> c2 = Singleton.Lazy.Lazy3::getInstance;

        ExecutorService service = Executors.newFixedThreadPool(2);
        Future<Singleton.Lazy.Lazy3> f1 = service.submit(c1);
        Future<Singleton.Lazy.Lazy3> f2 = service.submit(c2);
        Singleton.Lazy.Lazy3 lazy1 = f1.get();
        Singleton.Lazy.Lazy3 lazy2 = f2.get();

        System.out.println(lazy1 == lazy2);
    }

    /**
     * 结论：单例对象放在静态内部类，随着类的创建而创建，推荐
     */
    void testLazy4() throws ExecutionException, InterruptedException {
        //创建两个线程，测试线程是否安全
        Callable<Singleton.Lazy.Lazy4> c1 = Singleton.Lazy.Lazy4::getInstance;
        Callable<Singleton.Lazy.Lazy4> c2 = Singleton.Lazy.Lazy4::getInstance;

        ExecutorService service = Executors.newFixedThreadPool(2);
        Future<Singleton.Lazy.Lazy4> f1 = service.submit(c1);
        Future<Singleton.Lazy.Lazy4> f2 = service.submit(c2);
        Singleton.Lazy.Lazy4 lazy1 = f1.get();
        Singleton.Lazy.Lazy4 lazy2 = f2.get();

        // 线程睡眠时间越长，越大概率为false，不安全
        System.out.println(lazy1 == lazy2);
    }

}
